# -*- encoding: utf-8 -*-

import os
import sys
import json
import time
import asyncio
import argparse
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import PlainTextResponse, JSONResponse, HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from Util.sqliteDict import SQLiteDict

# 全局配置变量
config = {
    'port': 1145,
    'data_dir': './data',
    'initial_file': None
}

# 创建数据目录
os.makedirs(config['data_dir'], exist_ok=True)

# 全局数据库实例
db = None


def get_db():
    """获取数据库实例"""
    global db
    if db is None:
        db_path = os.path.join(config['data_dir'], 'db.sqlite')
        db = SQLiteDict(db_path)
    return db


def parse_arguments():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(description='Net SafeIO HTTP Server with SQLite')
    parser.add_argument('-p', '--port', type=int, default=1145,
                        help='设置绑定的端口号 (默认: 1145)')
    parser.add_argument('-d', '--dir', type=str, default='./data',
                        help='设置数据存储目录 (默认: ./data)')
    parser.add_argument('-f', '--file', type=str,
                        help='设置初始JSON文件路径,用于数据迁移')
    parser.add_argument('-e', '--export', type=str,
                        help='设置导出JSON文件路径,用于数据导出')
    return parser.parse_args()


def load_initial_data(file_path):
    """从JSON文件加载初始数据"""
    if not file_path or not os.path.exists(file_path):
        return

    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            data = json.load(f)

        # 确保数据是字典类型
        if isinstance(data, dict):
            # 清空现有数据
            db_instance = get_db()
            db_instance.clear()
            # 写入新数据
            for key, value in data.items():
                db_instance[key] = str(value)  # 确保值是字符串类型
            print(f"成功从 {file_path} 加载初始数据")
        else:
            print(f"警告: {file_path} 中的数据格式不正确，应为字典类型")
    except Exception as e:
        print(f"加载初始数据失败: {e}")


def export_data(file_path):
    """导出数据到JSON文件"""
    if not file_path:
        return

    try:
        db_instance = get_db()
        data = {key: db_instance[key] for key in db_instance.keys()}
        
        # 确保目录存在
        dir_path = os.path.dirname(file_path)
        if dir_path:  # 只有当目录路径不为空时才创建目录
            os.makedirs(dir_path, exist_ok=True)
        
        with open(file_path, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        
        print(f"成功导出数据到 {file_path}")
    except Exception as e:
        print(f"导出数据失败: {e}")


app = FastAPI(
    title="Net SafeIO API",
    description="基于Python+LevelDB+FastAPI的HTTP数据存储服务",
    version="1.0.0"
)

# 挂载静态文件目录
app.mount("/static", StaticFiles(directory="static"), name="static")

# 设置模板
templates = Jinja2Templates(directory="static")


@app.get("/read_data", response_class=JSONResponse)
async def read_data():
    """读取所有数据"""
    try:
        db_instance = get_db()
        data = {key: db_instance[key] for key in db_instance.keys()}
        return data
    except Exception as e:
        raise HTTPException(status_code=500, detail="internal error")


@app.post("/write_data", response_class=PlainTextResponse)
async def write_data(request: Request):
    """合并数据"""
    try:
        content_type = request.headers.get("content-type", "").lower()
        if "json" not in content_type:
            raise HTTPException(status_code=400, detail="bad request content: requires json type")

        body = await request.body()
        if not body:
            raise HTTPException(status_code=400, detail="non-full content")

        try:
            new_data = json.loads(body.decode('utf-8'))
        except json.JSONDecodeError:
            raise HTTPException(status_code=400, detail="bad json")

        # 确保数据是字典类型
        if not isinstance(new_data, dict):
            raise HTTPException(status_code=400, detail="bad json")

        # 合并数据
        db_instance = get_db()
        for key, value in new_data.items():
            db_instance[key] = str(value)  # 确保值是字符串类型

        return "ok"
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=507, detail="io error")


@app.post("/override", response_class=PlainTextResponse)
async def override_data(request: Request):
    """覆写数据"""
    try:
        content_type = request.headers.get("content-type", "").lower()
        if "json" not in content_type:
            raise HTTPException(status_code=400, detail="bad request content: requires json type")

        body = await request.body()
        if not body:
            raise HTTPException(status_code=400, detail="non-full content")

        try:
            new_data = json.loads(body.decode('utf-8'))
        except json.JSONDecodeError:
            raise HTTPException(status_code=400, detail="bad json")

        # 确保数据是字典类型
        if not isinstance(new_data, dict):
            raise HTTPException(status_code=400, detail="bad json")

        # 清空现有数据并写入新数据
        db_instance = get_db()
        db_instance.clear()
        for key, value in new_data.items():
            db_instance[key] = str(value)  # 确保值是字符串类型

        return "ok"
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=507, detail="io error")


@app.get("/get/{key}", response_class=JSONResponse)
async def get_data(key: str):
    """获取单个键值对"""
    try:
        db_instance = get_db()
        if key not in db_instance:
            raise HTTPException(status_code=404, detail="Key not found")
        return {key: db_instance[key]}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail="internal error")


@app.delete("/delete/{key}", response_class=PlainTextResponse)
async def delete_data(key: str):
    """删除单个键值对"""
    try:
        db_instance = get_db()
        if key not in db_instance:
            raise HTTPException(status_code=404, detail="Key not found")
        del db_instance[key]
        return "ok"
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail="internal error")


@app.get("/", response_class=HTMLResponse)
async def read_root():
    """主页路由，返回WebUI"""
    with open("static/index.html", "r", encoding="utf-8") as f:
        html_content = f.read()
    return HTMLResponse(content=html_content)


def main():
    """主函数"""
    # 解析命令行参数
    args = parse_arguments()
    config['port'] = args.port
    config['data_dir'] = args.dir
    config['initial_file'] = args.file

    # 更新数据目录
    os.makedirs(config['data_dir'], exist_ok=True)

    # 加载初始数据
    if config['initial_file']:
        load_initial_data(config['initial_file'])
    
    # 导出数据
    if args.export:
        export_data(args.export)
        # 如果只是导出数据，不需要启动服务器
        return

    print(f"启动服务器，端口: {config['port']}")
    print(f"数据目录: {config['data_dir']}")
    if config['initial_file']:
        print(f"初始数据文件: {config['initial_file']}")

    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=config['port'])


if __name__ == "__main__":
    main()
